package com.lzw.breezeNovel.webApp.service.impl.novel;

import com.lzw.breezeNovel.common.exception.BaseException;
import com.lzw.breezeNovel.common.login.LoginUser;
import com.lzw.breezeNovel.common.login.LoginUserHolder;
import com.lzw.breezeNovel.model.entity.pojo.novel.Book;
import com.lzw.breezeNovel.model.entity.pojo.novel.Rating;
import com.lzw.breezeNovel.model.entity.pojo.user.UserInfo;
import com.lzw.breezeNovel.model.entity.query.PaginationResultQuery;
import com.lzw.breezeNovel.model.entity.query.Search;
import com.lzw.breezeNovel.model.entity.query.SimplePage;
import com.lzw.breezeNovel.model.enums.novel.BookStatus;
import com.lzw.breezeNovel.webApp.mapper.novel.BookMapper;
import com.lzw.breezeNovel.webApp.mapper.novel.BookSelfMapper;
import com.lzw.breezeNovel.webApp.mapper.novel.RatingMapper;
import com.lzw.breezeNovel.webApp.mapper.user.UserInfoMapper;
import com.lzw.breezeNovel.webApp.service.novel.BookService;
import com.lzw.breezeNovel.webApp.vo.novel.BookVo;
import com.lzw.breezeNovel.webApp.vo.novel.ChapterVo;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

/**
 * @author 清风明月
 * @Package com.lzw.breezeNovel.webApp.service.novel.impl
 * @date 2025/3/2
 * @description 小说的服务实现类
 */
@Slf4j
@Service
@SuppressWarnings("all")
public class BookServiceImpl implements BookService {

    /**
     * 注入mapper
     */
    @Autowired
    private BookMapper bookMapper;

    /**
     * 注入用户mapper
     */
    @Autowired
    private UserInfoMapper userInfoMapper;

    /**
     * 注入评分表
     */
    @Autowired
    private RatingMapper ratingMapper;

    /**
     * 注入自定义线程池
     */
    @Autowired
    private ThreadPoolExecutor taskExecutor;

    /**
     * 注入书架mapper
     */
    @Autowired
    private BookSelfMapper bookSelfMapper;


    /**
     * 获取限时免费的小说
     * @return
     */
    @Override
    public List<BookVo> getFreeBooks() {
        //查询限时免费小说
        List<Book> books = bookMapper.getFreeBooks();
        //对结果进行遍历
        List<BookVo> bookVos = getBookVos(books);
        return bookVos;
    }

    /**
     * 获取最新小说
     * @return
     */
    @Override
    public List<BookVo> getNewBooks() {
        //查询最新小说
        List<Book> books = bookMapper.getNewBooks();
        //循环遍历
        //对结果进行遍历
        List<BookVo> bookVos = getBookVos(books);
        return bookVos;
    }

    /**
     * 分页获取最新小说
     * @param page
     * @param pageSize
     * @return
     */
    @Override
    public  PaginationResultQuery<BookVo> getNewBooksByPage(Integer page, Integer pageSize) {
        //对分页查询的条件进行判断
        page = Math.max(Optional.ofNullable(page).orElse(1), 1);
        pageSize = Math.max(Optional.ofNullable(pageSize).orElse(10), 1);;
        //查询最新的小说数量
        int count = bookMapper.selectCount();
        //创建分页对象
        SimplePage simplePage = new SimplePage(count, page, pageSize);
        //判断是否有数据
        if(count == 0)
        {
            return new PaginationResultQuery<>(0, pageSize, page, 0, Collections.emptyList());
        }
        //计算页码和总页数
        simplePage.action();
        //进行分页查询
        List<Book> books = bookMapper.getNewBooksByPage(simplePage);
        //对结果进行遍历
        List<BookVo> bookVos = getBookVos(books);
        //封装分页查询结果对象
        PaginationResultQuery<BookVo> pages = new PaginationResultQuery<BookVo>(count, pageSize, page, simplePage.getPageTotal(), bookVos);
        return pages;
    }

    /**
     * 根据小说的类型获取数据
     * @param type
     * @return
     */
    @Override
    public List<BookVo> getBooksByType(String type) {
       List<Book> books =  bookMapper.selectBookByType(type);
       List<BookVo> bookVos = getBookVos(books);
        return bookVos;
    }

    /**
     * 根据小说类型分页获取数据
     * @param type
     * @param page
     * @param pageSize
     * @return
     */
    @Override
    public PaginationResultQuery<BookVo> getBooksByTypeByPage(String type, Integer page, Integer pageSize) {
        //对分页查询的条件进行判断
        page = Math.max(Optional.ofNullable(page).orElse(1), 1);
        pageSize = Math.max(Optional.ofNullable(pageSize).orElse(10), 1);;
        //查询最新的小说数量
        int count = bookMapper.selectCountByType(type);
        //判断是否有数据
        if(count == 0)
        {
            return new PaginationResultQuery<>(0, pageSize, page, 0, Collections.emptyList());
        }
        //创建分页对象
        SimplePage simplePage = new SimplePage(count, page, pageSize);
        //计算页码和总页数
        simplePage.action();
        //进行分页查询
        List<Book> books = bookMapper.getBooksByTypeByPage(simplePage);
        //对结果进行遍历
        List<BookVo> bookVos = getBookVos(books);
        //封装分页查询结果对象
        PaginationResultQuery<BookVo> pages = new PaginationResultQuery<BookVo>(count, pageSize, page, simplePage.getPageTotal(), bookVos);
        return pages;
    }


    /**
     * 根据小说id获取小说信息
     * @param bookId
     * @return
     */
    @Override
    @Transactional(readOnly = true)
    public BookVo getBookById(Long bookId) {
        LoginUser loginUser = LoginUserHolder.getLoginUser();
        //获取当前用户的手机号
        String phone = loginUser.getPhone();
        // 异步获取用户信息
        CompletableFuture<UserInfo> userFuture = CompletableFuture.supplyAsync(() -> {
            return userInfoMapper.selectByPhone(loginUser.getPhone());
        }, taskExecutor);

        // 异步获取书籍信息
        CompletableFuture<Book> bookFuture = CompletableFuture.supplyAsync(() -> {
            return bookMapper.selectById(bookId);
        }, taskExecutor);

        // 组合异步任务
        CompletableFuture<BookVo> resultFuture = userFuture.thenCombineAsync(bookFuture, (userInfo, book) -> {
            if (book == null) {
                throw new BaseException(404, "没有查询到数据");
            }
            BookVo bookVo = new BookVo();
            //异步根据书籍id从书架里面获取书籍信息判断是否加入书架了
            CompletableFuture<Boolean> booleanCompletableFuture = CompletableFuture.supplyAsync(() -> {
                return bookSelfMapper.selectByUserIdAndBookId(userInfo.getUserId(), bookId) != 0;
            }, taskExecutor);

            try {
                // 同步拷贝基础属性
                BeanUtils.copyProperties(book, bookVo);
                // 异步处理评分信息
                CompletableFuture<Void> ratingFuture = CompletableFuture.runAsync(() -> {
                    Rating rating = ratingMapper.selectRatingByBookIdAndUserId(Math.toIntExact(bookId), userInfo.getUserId());
                    bookVo.setRated(rating != null);
                    if (rating != null) {
                        bookVo.setScore(rating.getScore());
                    }
                }, taskExecutor);

                // 异步处理章节信息
                CompletableFuture<List<ChapterVo>> chaptersFuture = CompletableFuture.supplyAsync(() ->
                                book.getChapters().parallelStream()
                                        .map(chapter -> {
                                            ChapterVo chapterVo = new ChapterVo();
                                            BeanUtils.copyProperties(chapter, chapterVo);
                                            return chapterVo;
                                        })
                                        .filter(chapterVo -> chapterVo != null)
                                        .collect(Collectors.toList())
                        , taskExecutor);

                // 等待是否加入书架的结果
                bookVo.setIsAddShelf(booleanCompletableFuture.join());
                // 等待章节信息处理完成并设置到 bookVo 中
                bookVo.setChapters(chaptersFuture.join());

                // 处理书籍状态
                bookVo.setStatus(BookStatus.getDescByCode(book.getStatus()));
                return bookVo;
            } catch (Exception e) {
                log.error("对象拷贝失败", e);
                throw new BaseException(500, "系统异常");
            }
        }, taskExecutor);
        // 处理异步操作结果并捕获可能的异常
        return resultFuture.exceptionally(ex -> {
            // 获取异常的原始原因
            Throwable cause = ex.getCause();
            // 判断原始原因是否为BaseException类型，如果是则直接抛出
            if (cause instanceof BaseException) {
                throw (BaseException) cause;
            }
            // 记录错误日志
            log.error("服务处理异常", ex);
            // 抛出自定义异常，表示服务处理过程中出现错误
            throw new BaseException(500, "服务处理异常");
        }).join();
    }

    /**
     * 模糊
     * @param bookId
     * @param keyword
     * @return
     */
    @Override
    public PaginationResultQuery<BookVo> searchBook(@NotNull Search search) {
        //对分页查询的条件进行判断
        Integer page = Math.max(Optional.ofNullable(search.getPageNum()).orElse(1), 1);
        Integer pageSize = Math.max(Optional.ofNullable(search.getPageSize()).orElse(10), 1);
        //分装分页对象
        Integer start = (page - 1) * pageSize;
        //根据条件查询书籍信息
        List<Book> books = bookMapper.selectBookByKeyword(search.getKeyword(), start, pageSize);
        if (books.size() > 0) {
            //对结果进行遍历
            List<BookVo> bookVos = getBookVos(books);
            //封装分页查询结果对象
            PaginationResultQuery<BookVo> pages = new PaginationResultQuery<BookVo>(null, pageSize, page, bookVos.size(), bookVos);
            return pages;
        }
        return null;
    }


    /**
     * 循环遍历查询的结果
     */
    public List<BookVo> getBookVos(@NotNull List<Book> books) {
        //循环遍历
        List<BookVo> bookVos = books.stream().map(book -> {
            //创建BookVo对象
            BookVo bookVo = new BookVo();
            //进行对象拷贝
            try {
                BeanUtils.copyProperties(book, bookVo);
                //获取小说的状态
                Integer status = book.getStatus();
                String statusDesc = BookStatus.getDescByCode(status);
                bookVo.setStatus(statusDesc);
                return bookVo;
            } catch (Exception e) {
                log.error("对象拷贝失败", e);
                throw new BaseException(500,"拷贝对象时出现异常");
            }
        }).filter(bookVo -> bookVo != null).collect(Collectors.toList());
        return bookVos;
    }
}
